#include "Resource.h"

Resource::Resource(LPDIRECT3DDEVICE9 d3ddev)
{
	/**
	Initialize the class Resource members
	*/

	this->d3ddev = d3ddev;
	world_physics = NULL;
	doSleep = false;

	texture_resource = new std::vector<Texture*>;

	nCulled = 0;
}

Resource::~Resource()
{
	/**
	Delete all created objects then delete the physics.
	*/

	if( vsprite_resource.size() != 0 )
	{
		for(int i=0; i<int(vsprite_resource.size()); i++)
			delete vsprite_resource[i];
		
		vsprite_resource.clear();
		msprite_resource.clear();
	}

	if( world_physics != NULL )
		delete world_physics;

	if( texture_resource->size() != 0 )
		for( int i=0; i<(int)texture_resource->size();i++)
			delete texture_resource->at(i);
	delete texture_resource;
}

Texture * Resource::GetTexture(int SurfaceId)
{
	return texture_resource->at(SurfaceId);
}

void Resource::initPhysics(float width, float height, float gravity)
{
	/**
	Initialize the physics world. values for width and height should be positive unless you want a
	upside down world. Automatically adds a representation of the how big the world is and it's
	position to be able to render and make it visible.
	*/

	b2AABB worldAABB;
	worldAABB.lowerBound.Set(-width, -height);
	worldAABB.upperBound.Set( width,  height);

	world_physics = new b2World(worldAABB, b2Vec2(0.0f, gravity), doSleep);

	Sprite * physicsCage = new Sprite();
	physicsCage->init(d3ddev, world_physics);
	physicsCage->setScale(width, height);
	physicsCage->setPosition(0.0f, 0.0f, 58.0f);
	physicsCage->WireMode();

	vsprite_resource.push_back( physicsCage );
}

void Resource::AddObject(std::string object_name, int object_type)
{
	/**
	Adds objects to the resource. Can add different types (right now thre is only one type)
	Default is to use sprite.
	Also object must be named and have different names.
	*/

	switch( object_type )
	{
		case SPRITE:
		{
			Entity * object = new Sprite();			//Create sprite
			object->init(d3ddev, world_physics);	//Initialize Sprite

			vsprite_resource.push_back( object );	//Push instance into vector container
			msprite_resource.insert( MAP_SPRITE::value_type(object_name, object) );	//Push instance into map container

			break;
		}

		case MESH:
		{
			Entity * object = new CMesh();
			object->init(d3ddev, world_physics);

			vsprite_resource.push_back( object );
			msprite_resource.insert( MAP_SPRITE::value_type(object_name, object) );
		}
		break;

		default:
			_cprintf("%s\n", "Resource::AddObject -> Object Type Does Not Exist!");
		break;
	}

}

void Resource::AddObject(Entity * object)
{
		object->init(d3ddev, world_physics);

		vsprite_resource.push_back( object );
		msprite_resource.insert( MAP_SPRITE::value_type("", object) );
}

void Resource::AddTexRes(std::string tpath, int id)
{
	Texture * tex = new Texture(d3ddev);
	tex->LoadTexture(tpath.c_str(), id);
	

	texture_resource->push_back( tex );
}

Entity * Resource::GetObject(std::string object_name)
{
	/**
	Returns the object by name.
	*/
	Entity * entity_object = NULL;

	if( msprite_resource.find( object_name ) != msprite_resource.end() )
		entity_object = msprite_resource.find( object_name )->second;

	return entity_object;
}

Entity * Resource::GetObject(int index)
{
	/**
	Returns the object by index.
	*/

	Entity * entity_object = NULL;

	if( vsprite_resource.size() != 0 )
		entity_object = vsprite_resource[index];

	return entity_object;
}

int Resource::NumberOfObjects()
{
	/**
	Returns the max number of objects added. Including the physical world.
	*/

	return vsprite_resource.size();
}

void Resource::Render(Camera * camera)
{
	/**
	Render all the objects. Also set the time step for the physics world.
	*/

	// Update Physics
	nCulled = 0;
	world_physics->Step(1.0f/240.0f, 100); 
	camera->buildFrustum(d3ddev);

	//Render all objects
	for(int i=0; i<(int)vsprite_resource.size(); i++)
	{
		if(camera != NULL)
				vsprite_resource[i]->setCamera(camera);

		if( camera->sphereInFrustum( vsprite_resource[i], 1.0f*vsprite_resource[i]->GetScaleX()*vsprite_resource[i]->GetScaleY() ) )
		{
			vsprite_resource[i]->Render(d3ddev);
			nCulled++;
		}
	}

}